//  1.首先有一个静态的install方法，判断vuerouter是否已经被注入
//  2.注入完毕后需要每个组件通过$router访问被实例化的VueRouter，需要用到Vue.mixin混入功能将router挂载到vue的prototype上
//  3.实例化VueRouter,初始化参数options,data,routeMap
//  4.createRouteMap,我们只是模拟，这里不做routes对象的递归
//  5.创建router-link,router-view组件。---initComponents
//  6.init方法。将createRouteMap，initComponents合并在初始化的时候执行
//  7.为router-link组建添加事件，使用history.pushState方法改变地址栏，并修改this.data.current触发视图更新
//  8.initEvent.监听popstate事件，触发视图更新
//  9.区分hash,history模式，hash模式就是a标签的超链接用#链接，切换路由页面自动更新，history模式，更像是正真的路由
//  需要使用history.pushState()手动更新地址栏，且阻止a标签的超链接默认行为。
//  10.浏览器的退后和前进在hash和history模式下各不相同

let _Vue = null;
export default class VueRouter {
    static install(Vue) {
        if (VueRouter.install.installed && _Vue === Vue) return;
        VueRouter.install.installed = true;
        _Vue = Vue;

        _Vue.mixin({
            beforeCreate() {
                if (this.$options.router) {
                    _Vue.prototype.$router = this.$options.router;
                }
            }
        })
    }

    constructor(options) {
        // 储存传递的参数，如mode,routes
        this.options = options;
        // 将routes转换为键值对形式的数据存储，我们这里不考虑子路由了，需要递归创建
        this.routeMap = {};
        //  记录当前路由，当路由改变时，要及时刷新组件，所以需要Vue.obserable()方法将对象转换为响应式数据
        this.data = _Vue.observable({
            current: '/'
        })

        this.init();
    }

    init() {
        this.createRouteMap();
        this.initComponents(_Vue);
        this.initEvent()
    }

    createRouteMap() {
        this.options.routes.forEach(route => {
            let key = route.path;
            this.routeMap[key] = route.component;
        })
    }

    initComponents(Vue) {
        const self = this;
        // 添加全局route-link组件
        Vue.component('router-link', {
            props: {
                to: String
            },
            methods: {
                clickHandler(event) {
                    // hash模式下，切换路由浏览器不会刷新，我们只需要改变响应式数据更新组件即可
                    self.data.current = this.to;
                    if (self.isHash()) return;
                    if (self.isHistory()) {
                        event.preventDefault();
                        history.pushState({}, '', this.to)
                    }
                }
            },
            render(createElement) {
                // 当是hash模式时，链接前有一个#
                const href = self.isHash() ? `#${this.to}` : this.to;
                return createElement('a', {
                    attrs: {
                        href
                    },
                    on: {
                        click: this.clickHandler
                    }
                }, [this.$slots.default])
            }
        })

        // 创建router-view组件
        Vue.component('router-view', {
            render(createElement) {
                // 因为this.data.current是响应式的，所以当属性改变时，组件可以重新渲染
                const component = self.routeMap[self.data.current];
                return createElement(component)
            }
        })
    }

    initEvent() {
        window.addEventListener('popstate', () => {
            if (this.isHistory()) {
                this.data.current = window.location.pathname
            }
        })

        window.addEventListener('hashchange', (e) => {
            if (this.isHash()) {
                this.data.current = window.location.hash.substr(1);
            }
        })
    }

    isHash() {
        return this.options.mode === 'hash';
    }

    isHistory() {
        return this.options.mode === 'history';
    }
}